/**
 * 
 */
package de.oszimtcc.timetablehelper;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import de.oszimtcc.framework.Logger;
import de.oszimtcc.timetable.TimetableApplication;
import de.oszimtcc.timetablecore.Timetable;

/**
 * @author Kooki
 * Singelton to managing a SQLite Database to cache informations
 */
public class RequestCache 
{
	public static final String databaseName = "OSZIMTRequestCache";
	public static final String storedTimetables = "storedTimetables";
	
	private static RequestCache instance = null;
	private static Map<String, RequestCache> instanceMap = new HashMap<String, RequestCache>();
	private SQLiteDatabase database;
	
	/**
	 * @author Kooki
	 * helper which creates the database tables if not existing.
	 */
	public class MyOpenHelper extends SQLiteOpenHelper 
	{
		private static final int DATABASE_VERSION = 1;

		MyOpenHelper(Context context) 
		{
	        super(context, databaseName, null, DATABASE_VERSION);
	    }
		
		MyOpenHelper(Context context,String pTableName) 
		{
	        super(context, databaseName + pTableName, null, DATABASE_VERSION);
	    }

	    @Override
	    public void onCreate(SQLiteDatabase db) 
	    {
		    // prepare tables    		
	    	String sql = "create table if not exists " + storedTimetables + "(id integer primary key autoincrement,class varchar(10), timetable blob,starttime int, requesttime datetime default current_timestamp)";
	    	db.execSQL(sql);
	    	Logger.Debug("prepare new table: " + storedTimetables + "\n with : " + sql);
	    	
	    }

		@Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 
		{
			Logger.Debug("Check for database upgrade for DATABASE_VERSION("+DATABASE_VERSION+")");
			Logger.Debug("db-Version : " + db.getVersion());
			Logger.Debug("oldVersion : " + oldVersion);
			Logger.Debug("newVersion : " + newVersion);
	        if(oldVersion < DATABASE_VERSION) 
	        {
	        	Logger.Debug("update needed");
	        }
        }
	}

	
	
	/**
	 * private Singleton constructor which opens the internal database (creating it if neccessary)
	 */
	private RequestCache() 
	{
		MyOpenHelper helper = new MyOpenHelper(TimetableApplication.getInstance().getApplicationContext());
	    database = helper.getWritableDatabase();
	    
	    Logger.Debug("opened internal database");
	}
	
	private RequestCache(String pClassName) 
	{
		MyOpenHelper helper = new MyOpenHelper(TimetableApplication.getInstance().getApplicationContext(),pClassName);
	    database = helper.getWritableDatabase();
	    
	    Logger.Debug("opened internal database");
	}
	
	@Override
    protected void finalize() throws Throwable 
    {
    	// close database
        if(database!=null) 
        {
        	if(database.isOpen()) 
        	{
        		database.close();
        		Logger.Debug("closed database");
        	}
        }
        super.finalize();
    }
	
	/**
	 * @return reference to the StarCache singleton. Use this method if you need to access the StarCache.
	 */
	public static RequestCache getInstance() 
	{
		return instance == null ? new RequestCache() : instance;
	}
	
	public static RequestCache getInstance(String pClassName) 
	{
		if(instanceMap.get(pClassName) == null)
		{
			instanceMap.put(pClassName, new RequestCache(pClassName));
			return instanceMap.get(pClassName);
		}
		return instanceMap.get(pClassName);
	}
	
	public static void Close()
	{
		if(instance != null)
	        try
            {
	            instance.finalize();
            }
            catch(Throwable e)
            {
            }
	}
	
	public void AddTimetable(Timetable pToStore)
	{
		database.insertWithOnConflict(storedTimetables, null, pToStore.ToContentValue(), SQLiteDatabase.CONFLICT_REPLACE);
	}
	
	public void ChangeLastTimetable(Timetable pToStore)
	{
		String where = "requesttime=(SELECT MAX(requesttime) FROM " + storedTimetables + ")";
		database.update(storedTimetables, pToStore.ToContentValue(), where, null);
	}
	
	public Timetable GetLatestTimetable()
	{
		String statement = "requesttime=(SELECT MAX(requesttime) FROM " + storedTimetables + ")";
		Cursor cursor = database.query(storedTimetables, new String[]{"timetable","requesttime"}, statement, null, null, null, null, null);
		if(cursor.getCount() == 0)  
		{
			cursor.close();
			Logger.Debug("No Timetable was found on internal Database");
    		return null;
    	}
		if(cursor.moveToFirst()) 
		{
			Logger.Debug("	Timetable from :  " + cursor.getString(cursor.getColumnIndex("requesttime")));
    	}
		Timetable toReturn = ObjectSerializator.DeserializeTimetable(cursor.getBlob(cursor.getColumnIndex("timetable")));
		cursor.close();
    	return toReturn;
    }
	
	public Date GetLastTimetableRequestTime()
	{
		Date resultDate = null;
		String statement = "requesttime=(SELECT MAX(requesttime) FROM " + storedTimetables + ")";
		Cursor cursor = database.query(storedTimetables, new String[]{"requesttime"}, statement, null, null, null, null, null);
		if(cursor.getCount() == 0)  
		{
			cursor.close();
			Logger.Debug("No Timetable was found on internal Database");
    		return null;
    	}
		if(cursor.moveToFirst()) 
		{
			Logger.Debug("	Timetable from :  " + cursor.getString(cursor.getColumnIndex("requesttime")));
    		resultDate = new Date(cursor.getString(cursor.getColumnIndex("requesttime")).replace("-", "/"));	
    	}
		cursor.close();
    	return resultDate;	
    }
	
	public Boolean IsRequestNeeded()
	{
		long lastTime = 0;
		try
		{
			lastTime = this.getInstance(TimetableApplication.getInstance().getActivity().GetStringPreference("Class")).GetLastTimetableRequestTime().getTime();
		}
		catch(Exception e)
		{
			Logger.Error("Error on get time : " + e);
			return true;
		}
		long now = new Date().getTime();
		long duration = now - lastTime;
		return duration >= (86400000);
	}
}

